library(DNAcopy)
library(foreach)
library(plyr)
library(dplyr)
source("R/CNV_functions_AKS12202017.R")

Introduction

The following code generates figures for the Halobacterium CNV manuscript. This code uses the CNV package DNAcopy to analyze both gene expression and ChIP microarrays.

## All gene expression microarrays (numbers are standardized z scores)
all_data <- read.delim(file = "data/Gene_expression_Master.txt", row.names = 1)
## Empty array to be filled for the generation of segment maps
rarray <- read.delim(file = "data/rarray_allloci.txt")

GE microarray data analysis

The following commented chunk takes a long time to run. A preprocessed object, provided in the github data/ folder, can be loaded instead (see below).

# CNA.ob <- CNA(all_data[,1:1154], all_data$Chr, all_data$Start,data.type = 'logratio', sampleid = colnames(all_data)[1:1154]) 
# smoothed <- smooth.CNA(CNA.ob)
# segsmot <- segment(smoothed, verbose = 0)  ## Set verbose = 1 if number of arrays is not huge
# save(segsmot, file = "data/segmented_GE_arrays.Rdata")
load(file = "data/segmented_GE_arrays.Rdata")

Figure 2, frequency map plots for megaplasmids pNRC100 and pNRC200

Generate maps of segments at different fragment size thresholds

t1f5k.copy <- copymap4(ref_array = rarray, seg_array = segsmot$output, threshold = 1, f.size = 5000)
t1f10k.copy <- copymap4(ref_array = rarray, seg_array = segsmot$output, threshold = 1, f.size = 10000)
t1f20k.copy <- copymap4(ref_array = rarray, seg_array = segsmot$output, threshold = 1, f.size = 20000)
t1f50k.copy <- copymap4(ref_array = rarray, seg_array = segsmot$output, threshold = 1, f.size = 50000)
t1f100k.copy <- copymap4(ref_array = rarray, seg_array = segsmot$output, threshold = 1, f.size = 100000)

Split copy maps by genomic elements

t1f5k.split <- split2(t1f5k.copy)
t1f10k.split <- split2(t1f10k.copy)
t1f20k.split <- split2(t1f20k.copy)
t1f50k.split <- split2(t1f50k.copy)
t1f100k.split <- split2(t1f100k.copy)

pNRC100 by gene expression segment size frequency, figure 2A left

pNRC200 by gene expression segment size frequency, figure 2A right

pNRC100 up and downregulated segment frequency map, Figure 2B left

pNRC200 up and downregulated segment frequency map, Figure 2B right

Figure 3 - GE segmentation up vs downregulation on main chromosome

chromosome, 20kb cutoff, Fig 3A

Calcluate functional enrichment in large GE frequency peaks on chromosome, fig 3B

#Find segments present in >= 5% of arrays, determine functional enrichments in chromosome
ge20k.5<-subset(t1f20k.split[[1]], (Thresh_up + Threshdown) >= 58)
#analysis in this code chunk relies upon https://github.com/amyschmid/histone_arCOG. Load source from there.
GE.5percent.arcog<-cogtest2(ge20k.5$GeneName, cogs, 0.05)
write.table (GE.5percent.arcog, file = "data/ge20k_freqpks_5percent_arCOGs.txt", sep = "\t") #Supplementary table?
#Determine which genes are in which arCOG categories, save as supplementary tables 
ge20k.5.pk1<-cogset(ge20k.5$GeneName, cogs, "Cell motility ")
write.table (ge20k.5.pk1, file = "ge20k_freqpks_5percent_pk1genes.txt",sep = "\t")
ge20k.5.pk2<-cogset(ge20k.5$GeneName, cogs, "Translation; ribosomal structure and biogenesis ")
write.table (ge20k.5.pk2, file = "ge20k_freqpks_5percent_pk2.txt", sep = "\t")
ge20k.5.pk3<-cogset(ge20k.5$GeneName, cogs, "Coenzyme transport and metabolism ")
write.table (ge20k.5.pk3, file = "ge20k_freqpks_5percent_pk3.txt", sep = "\t")
#similar code was used to calculate enrichments in gene expression data frequency peaks for megaplsmids from t1f20k.split[[2]] and t1f20k.split[[3]] except at 5k threshold.

ChIP microarray data analysis

Samples were parsed, median-centered, scaled, and segmented in independent batches before combining. The following code takes segmented chip array data and creates composite maps.

## Read in segmented ChIP data 
test <- read.delim(file = "data/all_clone_fragments_chIP.txt")
## Read in Trmb file 12 for example segmentation output
load(file = "data/trmb12.Rdata")

Example segmentation output, Trmb12 array

shown in Figure 1 example of genomic break point detection in ChIP arrays using DNAcopy

Analyzing: Trmb.12 

Figure 4

Segment grequency map of ChIP CNVs across 48 arrays, categorized by depletion and amplification events

# Generate copymap
crarray <- read.delim(file = "data/rarray_2400_moved_probes.txt")
crarray <- droplevels(crarray[crarray$Chr == "Chr",])
#5k threshold
chip.copy <- copymap4(ref_array = crarray, seg_array = test, threshold = 0.5, f.size = 5000)
chip.split <- split2(chip.copy)[[1]] %>% dplyr::arrange(Start)

Figure 4A

Frequency map of all ChIP CNVs, 5k threshold, 10% array threshold, 16 pks marked.

Fig 4B

Table 1: How many CNVs were detected in each array (GE and ChIP data)?

## First we consider GE data. Filter segments by significance across main chromosome.
all.clone.segs.GE<- segsmot$output
all.clone.segs.GE$seg.length <- (all.clone.segs.GE$loc.end - all.clone.segs.GE$loc.start)
segs.GE.20k <- subset (all.clone.segs.GE, seg.length >=20000)
segs.GE.20k <- subset (segs.GE.20k, chrom == "Chr" & (seg.mean >= 1 | seg.mean <= -1))
#for pNRC200
#segs.GE.20k.p200 <- subset (all.clone.segs.GE, seg.length >=20000)
segs.GE.20k.p200 <- subset (segs.GE.20k.p200, chrom == "pNRC200" & (seg.mean >= 1 | seg.mean <= -1))
#for pNRC100
#segs.GE.20k.p100 <- subset (all.clone.segs.GE, seg.length >=20000)
segs.GE.20k.p100 <- subset (segs.GE.20k.p100, chrom == "pNRC100" & (seg.mean >= 1 | seg.mean <= -1))
## Determine how many significant segments were contained within which GE arrays on main chromosome
freq.per.array20 <- plyr:::count(segs.GE.20k, "ID")
hist(freq.per.array20$freq, col = "grey", main = "Distribution of putative CNVs within each GE array", xlab = "Number of arrays") 
#for pNRC100
freq.per.array20.p100 <- plyr:::count(segs.GE.20k.p100, "ID")
hist(freq.per.array20.p100$freq, col = "grey", main = "Distribution of putative CNVs within each GE array", xlab = "Number of arrays") 
#for pNRC200
freq.per.array20.p200 <- plyr:::count(segs.GE.20k.p200, "ID")
hist(freq.per.array20.p200$freq, col = "grey", main = "Distribution of putative CNVs within each GE array", xlab = "Number of arrays") 
## Next we consider chip data. Filter segments by significance at 5k threshold
test$seg.length <- (test$loc.end - test$loc.start)
segs.chip.5k <- subset (test, seg.length >= 5000)
segs.chip.5k <- subset (segs.chip.5k, chrom == "Chr" & (seg.mean >= 0.5 | seg.mean <= -0.5))
## Determine how many significant segments were contained within which ChIP arrays 
freq.per.array.chip.5 <- plyr:::count(segs.chip.5k, "ID")
hist(freq.per.array.chip.5$freq, col = "grey", main = "Distribution of putative CNVs within each ChIP array", xlab = "Number of arrays")

Figure 5

Frequency map of all ChIP CNVs, with IS elements marked

sig.per.array<-read.delim ("data/num_signif_segs_per_arrays.txt")
hist(sig.per.array$total.signif.segs.per.array, breaks = 12, col = "grey", xlab = "Number CNVs per array", main = "CNVs are frequent")

Fig 5A: IS elements are detected within CNV regions.

Fig 5B: IS elements are associated with CNV regions at higher rate than expected by chance: bootstrapping results

plotchr_chip2(copymap = chip.split, narrays = 48, ymax = 80, ish_table = ish)
legend('topleft',legend=c('CNV','IS', '10% threshold'),col=c('black',rgb(0.1,0.1,.8,.3), 'red'),cex=1.2,bg='white', lty=c(1,2),lwd=2)
abline(h = 10, col = "red")

#points(x = sample(peaks7, 1000), y = c(rep(2,1000)), col = "green", pch =16, cex= .5)

Appendix

hist(ish.boot, col = "gray", xlim = c(0,15), xlab = "Number of IS elements\n in CNV regions", cex.lab=1.2, breaks =10)
abline( v = 14, lty = 2)

Note that the echo = FALSE parameter was added to the code chunk to prevent printing of the R code that generated the plot.

LS0tCnRpdGxlOiAiSGFsb19DTlZfZmlndXJlX2NvZGVfRklOQUwiCmRhdGU6ICJKYW51YXJ5IDE5IDIwMTgiCmVkaXRvcl9vcHRpb25zOgogIGNodW5rX291dHB1dF90eXBlOiBpbmxpbmUKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQKICBwZGZfZG9jdW1lbnQ6IGRlZmF1bHQKYXV0aG9yczogS2VlbHkgRHVsbWFnZSBhbmQgQW15IFNjaG1pZAotLS0KCgpgYGB7cn0KbGlicmFyeShETkFjb3B5KQpsaWJyYXJ5KGZvcmVhY2gpCmxpYnJhcnkocGx5cikKbGlicmFyeShkcGx5cikKCnNvdXJjZSgiUi9DTlZfZnVuY3Rpb25zX0FLUzEyMjAyMDE3LlIiKQpgYGAKCgoKIyMgSW50cm9kdWN0aW9uCgpUaGUgZm9sbG93aW5nIGNvZGUgZ2VuZXJhdGVzIGZpZ3VyZXMgZm9yIHRoZSBIYWxvYmFjdGVyaXVtIENOViBtYW51c2NyaXB0LiAgVGhpcyBjb2RlIHVzZXMgdGhlIENOViBwYWNrYWdlIEROQWNvcHkgdG8gYW5hbHl6ZSBib3RoIGdlbmUgZXhwcmVzc2lvbiBhbmQgQ2hJUCBtaWNyb2FycmF5cy4KCmBgYHtyfQojIyBBbGwgZ2VuZSBleHByZXNzaW9uIG1pY3JvYXJyYXlzIChudW1iZXJzIGFyZSBzdGFuZGFyZGl6ZWQgeiBzY29yZXMpCmFsbF9kYXRhIDwtIHJlYWQuZGVsaW0oZmlsZSA9ICJkYXRhL0dlbmVfZXhwcmVzc2lvbl9NYXN0ZXIudHh0Iiwgcm93Lm5hbWVzID0gMSkKCiMjIEVtcHR5IGFycmF5IHRvIGJlIGZpbGxlZCBmb3IgdGhlIGdlbmVyYXRpb24gb2Ygc2VnbWVudCBtYXBzCnJhcnJheSA8LSByZWFkLmRlbGltKGZpbGUgPSAiZGF0YS9yYXJyYXlfYWxsbG9jaS50eHQiKQoKYGBgCgoKCiMjIEdFIG1pY3JvYXJyYXkgZGF0YSBhbmFseXNpcwoKVGhlIGZvbGxvd2luZyBjb21tZW50ZWQgY2h1bmsgdGFrZXMgYSBsb25nIHRpbWUgdG8gcnVuLiAgQSBwcmVwcm9jZXNzZWQgb2JqZWN0LCBwcm92aWRlZCBpbiB0aGUgZ2l0aHViIGRhdGEvIGZvbGRlciwgY2FuIGJlIGxvYWRlZCBpbnN0ZWFkIChzZWUgYmVsb3cpLgpgYGB7ciwgbWVzc2FnZSA9IEZ9CiMgQ05BLm9iIDwtIENOQShhbGxfZGF0YVssMToxMTU0XSwgYWxsX2RhdGEkQ2hyLCBhbGxfZGF0YSRTdGFydCxkYXRhLnR5cGUgPSAnbG9ncmF0aW8nLCBzYW1wbGVpZCA9IGNvbG5hbWVzKGFsbF9kYXRhKVsxOjExNTRdKSAKIyBzbW9vdGhlZCA8LSBzbW9vdGguQ05BKENOQS5vYikKIyBzZWdzbW90IDwtIHNlZ21lbnQoc21vb3RoZWQsIHZlcmJvc2UgPSAwKSAgIyMgU2V0IHZlcmJvc2UgPSAxIGlmIG51bWJlciBvZiBhcnJheXMgaXMgbm90IGh1Z2UKIyBzYXZlKHNlZ3Ntb3QsIGZpbGUgPSAiZGF0YS9zZWdtZW50ZWRfR0VfYXJyYXlzLlJkYXRhIikKYGBgCmBgYHtyfQpsb2FkKGZpbGUgPSAiZGF0YS9zZWdtZW50ZWRfR0VfYXJyYXlzLlJkYXRhIikKYGBgCgojIyMgRmlndXJlIDIsIGZyZXF1ZW5jeSBtYXAgcGxvdHMgZm9yIG1lZ2FwbGFzbWlkcyBwTlJDMTAwIGFuZCBwTlJDMjAwCgpHZW5lcmF0ZSBtYXBzIG9mIHNlZ21lbnRzIGF0IGRpZmZlcmVudCBmcmFnbWVudCBzaXplIHRocmVzaG9sZHMKYGBge3J9CnQxZjVrLmNvcHkgPC0gY29weW1hcDQocmVmX2FycmF5ID0gcmFycmF5LCBzZWdfYXJyYXkgPSBzZWdzbW90JG91dHB1dCwgdGhyZXNob2xkID0gMSwgZi5zaXplID0gNTAwMCkKdDFmMTBrLmNvcHkgPC0gY29weW1hcDQocmVmX2FycmF5ID0gcmFycmF5LCBzZWdfYXJyYXkgPSBzZWdzbW90JG91dHB1dCwgdGhyZXNob2xkID0gMSwgZi5zaXplID0gMTAwMDApCnQxZjIway5jb3B5IDwtIGNvcHltYXA0KHJlZl9hcnJheSA9IHJhcnJheSwgc2VnX2FycmF5ID0gc2Vnc21vdCRvdXRwdXQsIHRocmVzaG9sZCA9IDEsIGYuc2l6ZSA9IDIwMDAwKQp0MWY1MGsuY29weSA8LSBjb3B5bWFwNChyZWZfYXJyYXkgPSByYXJyYXksIHNlZ19hcnJheSA9IHNlZ3Ntb3Qkb3V0cHV0LCB0aHJlc2hvbGQgPSAxLCBmLnNpemUgPSA1MDAwMCkKdDFmMTAway5jb3B5IDwtIGNvcHltYXA0KHJlZl9hcnJheSA9IHJhcnJheSwgc2VnX2FycmF5ID0gc2Vnc21vdCRvdXRwdXQsIHRocmVzaG9sZCA9IDEsIGYuc2l6ZSA9IDEwMDAwMCkKYGBgCgpTcGxpdCBjb3B5IG1hcHMgYnkgZ2Vub21pYyBlbGVtZW50cwpgYGB7cn0KdDFmNWsuc3BsaXQgPC0gc3BsaXQyKHQxZjVrLmNvcHkpCnQxZjEway5zcGxpdCA8LSBzcGxpdDIodDFmMTBrLmNvcHkpCnQxZjIway5zcGxpdCA8LSBzcGxpdDIodDFmMjBrLmNvcHkpCnQxZjUway5zcGxpdCA8LSBzcGxpdDIodDFmNTBrLmNvcHkpCnQxZjEwMGsuc3BsaXQgPC0gc3BsaXQyKHQxZjEwMGsuY29weSkKYGBgCgpwTlJDMTAwIGJ5IGdlbmUgZXhwcmVzc2lvbiBzZWdtZW50IHNpemUgZnJlcXVlbmN5LCBmaWd1cmUgMkEgbGVmdApgYGB7ciBmaWcud2lkdGggPSA4LCBmaWcuaGVpZ2h0ID0gNSwgZWNobyA9IEZ9CnBsb3RjaHIuY29sKHQxZjVrLnNwbGl0W1syXV0sMTE1NCwzNSwgJ29yYW5nZScpCmFkZF9jb3B5cGxvdCh0MWYxMGsuc3BsaXRbWzJdXSwxMTU0LCdncmVlbicpCmFkZF9jb3B5cGxvdCh0MWYyMGsuc3BsaXRbWzJdXSwxMTU0LCdibHVlJykKYWRkX2NvcHlwbG90KHQxZjUway5zcGxpdFtbMl1dLDExNTQsJ3B1cnBsZScpCmFkZF9jb3B5cGxvdCh0MWYxMDBrLnNwbGl0W1syXV0sMTE1NCwnYmxhY2snKQpsZWdlbmQoJ3RvcHJpZ2h0JywgY29sPWMoJ29yYW5nZScsJ2dyZWVuJywnYmx1ZScsJ3B1cnBsZScsJ2JsYWNrJyksIGxlZ2VuZD1jKCc1IGtiJywnMTAga2InLCAnMjAga2InLCc1MCBrYicsJzEwMCBrYicpLCBsd2Q9MywgYmc9J3doaXRlJywgY2V4PTEuMikKYGBgCgpwTlJDMjAwIGJ5IGdlbmUgZXhwcmVzc2lvbiBzZWdtZW50IHNpemUgZnJlcXVlbmN5LCBmaWd1cmUgMkEgcmlnaHQKYGBge3IgZmlnLndpZHRoID0gOCwgZmlnLmhlaWdodCA9IDUsIGVjaG8gPSBGfQpwbG90Y2hyLmNvbCh0MWY1ay5zcGxpdFtbM11dLDExNTQsMTAsICdvcmFuZ2UnKQphZGRfY29weXBsb3QodDFmMTBrLnNwbGl0W1szXV0sMTE1NCwnZ3JlZW4nKQphZGRfY29weXBsb3QodDFmMjBrLnNwbGl0W1szXV0sMTE1NCwnYmx1ZScpCmFkZF9jb3B5cGxvdCh0MWY1MGsuc3BsaXRbWzNdXSwxMTU0LCdwdXJwbGUnKQphZGRfY29weXBsb3QodDFmMTAway5zcGxpdFtbM11dLDExNTQsJ2JsYWNrJykKI2xlZ2VuZCgndG9wcmlnaHQnLCBjb2w9Yygnb3JhbmdlJywnZ3JlZW4nLCdibHVlJywncHVycGxlJywnYmxhY2snKSwgbGVnZW5kPWMoJzUga2InLCcxMCBrYicsICcyMCBrYicsJzUwIGtiJywnMTAwIGtiJyksIGx3ZD0zLCBiZz0nd2hpdGUnLCBjZXg9MS4yKQp0ZXh0KDE3NTAwMCwgOC4yLCAgY2V4ID0gMSwgZm9udCA9IDIgKQp0ZXh0ICgzMjUwMDAsIDguMiwgbGFiZWwgPSAyLCBjZXggPSAxLCBmb250PSAyKQpgYGAKCgpwTlJDMTAwIHVwIGFuZCBkb3ducmVndWxhdGVkIHNlZ21lbnQgZnJlcXVlbmN5IG1hcCwgRmlndXJlIDJCIGxlZnQKYGBge3IgZmlnLndpZHRoID0gNSwgZmlnLmhlaWdodCA9IDUsIGVjaG8gPSBGfQojIyByZWdpb25zIDIwa2Igb3IgbGFyZ2VyLCB0aHJlc2hvbGQgb2YgMSAKcGxvdHBsYXMuR0UyKGNvcHltYXAgPSB0MWYyMGsuc3BsaXRbWzJdXSwgbmFycmF5cyA9IDExNTQsIHlyYW5nZSA9IGMoMCwxMCkpCmBgYAoKcE5SQzIwMCB1cCBhbmQgZG93bnJlZ3VsYXRlZCBzZWdtZW50IGZyZXF1ZW5jeSBtYXAsIEZpZ3VyZSAyQiByaWdodApgYGB7ciBmaWcud2lkdGggPSA4LCBmaWcuaGVpZ2h0ID0gNSwgZWNobyA9IEZ9CiMjIHJlZ2lvbnMgMjBrYiBvciBsYXJnZXIsIHRocmVzaG9sZCBvZiAxIApwbG90cGxhcy5HRTIoY29weW1hcCA9IHQxZjIway5zcGxpdFtbM11dLCBuYXJyYXlzID0gMTE1NCwgeXJhbmdlID0gYygwLDEwKSkKYGBgCgojIyMgRmlndXJlIDMgLSBHRSBzZWdtZW50YXRpb24gdXAgdnMgZG93bnJlZ3VsYXRpb24gb24gbWFpbiBjaHJvbW9zb21lCgpjaHJvbW9zb21lLCAyMGtiIGN1dG9mZiwgRmlnIDNBCmBgYHtyIGZpZy53aWR0aCA9IDgsIGZpZy5oZWlnaHQgPSA1LCBlY2hvID0gRn0KIyMgcmVnaW9ucyAyMGtiIG9yIGxhcmdlciwgdGhyZXNob2xkIG9mIDEgCnBsb3RwbGFzLkdFMihjb3B5bWFwID0gdDFmMjBrLnNwbGl0W1sxXV0sIG5hcnJheXMgPSAxMTU0LCB5cmFuZ2UgPSBjKDAsMTApKQpgYGAKCkNhbGNsdWF0ZSBmdW5jdGlvbmFsIGVucmljaG1lbnQgaW4gbGFyZ2UgR0UgZnJlcXVlbmN5IHBlYWtzIG9uIGNocm9tb3NvbWUsIGZpZyAzQgpgYGB7cn0KI0ZpbmQgc2VnbWVudHMgcHJlc2VudCBpbiA+PSA1JSBvZiBhcnJheXMsIGRldGVybWluZSBmdW5jdGlvbmFsIGVucmljaG1lbnRzIGluIGNocm9tb3NvbWUKZ2UyMGsuNTwtc3Vic2V0KHQxZjIway5zcGxpdFtbMV1dLCAoVGhyZXNoX3VwICsgVGhyZXNoZG93bikgPj0gNTgpCgojY29nc2V0IGFuZCBjb2d0ZXN0IGZ1bmN0aW9ucyBhbHNvIGF2YWlsYWJsZSB2aWEgaHR0cHM6Ly9naXRodWIuY29tL2FteXNjaG1pZC9oaXN0b25lX2FyQ09HIGFuZCBEdWxtYWdlIGV0IGFsLiwgMjAxNSBtQmlvLgoKR0UuNXBlcmNlbnQuYXJjb2c8LWNvZ3Rlc3QyKGdlMjBrLjUkR2VuZU5hbWUsIGNvZ3MsIDAuMDUpCndyaXRlLnRhYmxlIChHRS41cGVyY2VudC5hcmNvZywgZmlsZSA9ICJkYXRhL2dlMjBrX2ZyZXFwa3NfNXBlcmNlbnRfYXJDT0dzLnR4dCIsIHNlcCA9ICJcdCIpICNTdXBwbGVtZW50YXJ5IHRhYmxlPwojRGV0ZXJtaW5lIHdoaWNoIGdlbmVzIGFyZSBpbiB3aGljaCBhckNPRyBjYXRlZ29yaWVzLCBzYXZlIGFzIHN1cHBsZW1lbnRhcnkgdGFibGVzIApnZTIway41LnBrMTwtY29nc2V0KGdlMjBrLjUkR2VuZU5hbWUsIGNvZ3MsICJDZWxsIG1vdGlsaXR5ICIpCndyaXRlLnRhYmxlIChnZTIway41LnBrMSwgZmlsZSA9ICJnZTIwa19mcmVxcGtzXzVwZXJjZW50X3BrMWdlbmVzLnR4dCIsc2VwID0gIlx0IikKZ2UyMGsuNS5wazI8LWNvZ3NldChnZTIway41JEdlbmVOYW1lLCBjb2dzLCAiVHJhbnNsYXRpb247IHJpYm9zb21hbCBzdHJ1Y3R1cmUgYW5kIGJpb2dlbmVzaXMgIikKd3JpdGUudGFibGUgKGdlMjBrLjUucGsyLCBmaWxlID0gImdlMjBrX2ZyZXFwa3NfNXBlcmNlbnRfcGsyLnR4dCIsIHNlcCA9ICJcdCIpCmdlMjBrLjUucGszPC1jb2dzZXQoZ2UyMGsuNSRHZW5lTmFtZSwgY29ncywgIkNvZW56eW1lIHRyYW5zcG9ydCBhbmQgbWV0YWJvbGlzbSAiKQp3cml0ZS50YWJsZSAoZ2UyMGsuNS5wazMsIGZpbGUgPSAiZ2UyMGtfZnJlcXBrc181cGVyY2VudF9wazMudHh0Iiwgc2VwID0gIlx0IikKCiNzaW1pbGFyIGNvZGUgd2FzIHVzZWQgdG8gY2FsY3VsYXRlIGVucmljaG1lbnRzIGluIGdlbmUgZXhwcmVzc2lvbiBkYXRhIGZyZXF1ZW5jeSBwZWFrcyBmb3IgbWVnYXBsc21pZHMgZnJvbSB0MWYyMGsuc3BsaXRbWzJdXSBhbmQgdDFmMjBrLnNwbGl0W1szXV0gZXhjZXB0IGF0IDVrIHRocmVzaG9sZC4KYGBgCgojIyBDaElQIG1pY3JvYXJyYXkgZGF0YSBhbmFseXNpcwoKU2FtcGxlcyB3ZXJlIHBhcnNlZCwgbWVkaWFuLWNlbnRlcmVkLCBzY2FsZWQsIGFuZCBzZWdtZW50ZWQgaW4gaW5kZXBlbmRlbnQgYmF0Y2hlcyBiZWZvcmUgY29tYmluaW5nLiAgVGhlIGZvbGxvd2luZyBjb2RlIHRha2VzIHNlZ21lbnRlZCBjaGlwIGFycmF5IGRhdGEgYW5kIGNyZWF0ZXMgY29tcG9zaXRlIG1hcHMuCmBgYHtyfQojIyBSZWFkIGluIHNlZ21lbnRlZCBDaElQIGRhdGEgCnRlc3QgPC0gcmVhZC5kZWxpbShmaWxlID0gImRhdGEvYWxsX2Nsb25lX2ZyYWdtZW50c19jaElQLnR4dCIpCiMjIFJlYWQgaW4gVHJtYiBmaWxlIDEyIGZvciBleGFtcGxlIHNlZ21lbnRhdGlvbiBvdXRwdXQKbG9hZChmaWxlID0gImRhdGEvdHJtYjEyLlJkYXRhIikKYGBgCgojIyMgRXhhbXBsZSBzZWdtZW50YXRpb24gb3V0cHV0LCBUcm1iMTIgYXJyYXkgCgpzaG93biBpbiBGaWd1cmUgMSBleGFtcGxlIG9mIGdlbm9taWMgYnJlYWsgcG9pbnQgZGV0ZWN0aW9uIGluIENoSVAgYXJyYXlzIHVzaW5nIEROQWNvcHkKYGBge3IgZmlnLndpZHRoID0gMTIsIGZpZy5oZWlnaHQgPSA1LCBlY2hvID0gRn0KdHJtYjEyLmNuYSA8LSBDTkEoZ2Vub21kYXQgPSBhcy5udW1lcmljKHRybWIxMi5tJFNjYWxlZCksIGNocm9tID0gdHJtYjEyLm0kQ2hyLCBtYXBsb2MgPSBhcy5udW1lcmljKHRybWIxMi5tJFBvc2l0aW9uKSwgc2FtcGxlaWQgPSAiVHJtYiAxMiIpCnRybWIxMi5zbW9vdGggPC0gc21vb3RoLkNOQSh0cm1iMTIuY25hKQp0cm1iMTIuc2Vnc21vdCA8LSBzZWdtZW50KHRybWIxMi5zbW9vdGgpCmNvcHlwbG90LmNoci5hbHQodHJtYjEyLnNlZ3Ntb3QsIGMoLTIsOCkpCmBgYAoKCgojIyMgRmlndXJlIDQKU2VnbWVudCBncmVxdWVuY3kgbWFwIG9mIENoSVAgQ05WcyBhY3Jvc3MgNDggYXJyYXlzLCBjYXRlZ29yaXplZCBieSBkZXBsZXRpb24gYW5kIGFtcGxpZmljYXRpb24gZXZlbnRzCmBgYHtyfQojIEdlbmVyYXRlIGNvcHltYXAKY3JhcnJheSA8LSByZWFkLmRlbGltKGZpbGUgPSAiZGF0YS9yYXJyYXlfMjQwMF9tb3ZlZF9wcm9iZXMudHh0IikKY3JhcnJheSA8LSBkcm9wbGV2ZWxzKGNyYXJyYXlbY3JhcnJheSRDaHIgPT0gIkNociIsXSkKCiM1ayB0aHJlc2hvbGQKY2hpcC5jb3B5IDwtIGNvcHltYXA0KHJlZl9hcnJheSA9IGNyYXJyYXksIHNlZ19hcnJheSA9IHRlc3QsIHRocmVzaG9sZCA9IDAuNSwgZi5zaXplID0gNTAwMCkKY2hpcC5zcGxpdCA8LSBzcGxpdDIoY2hpcC5jb3B5KVtbMV1dICU+JSBkcGx5cjo6YXJyYW5nZShTdGFydCkKCmBgYAoKIyMjIyBGaWd1cmUgNEEKRnJlcXVlbmN5IG1hcCBvZiBhbGwgQ2hJUCBDTlZzLCA1ayB0aHJlc2hvbGQsIDEwJSBhcnJheSB0aHJlc2hvbGQsIDE2IHBrcyBtYXJrZWQuCmBgYHtyIGZpZy53aWR0aCA9IDEyLCBmaWcuaGVpZ2h0ID0gNSwgZWNobyA9IEZ9CnBsb3RjaHIoY2hpcC5zcGxpdCwgNDgsIDgwKQphYmxpbmUgKGggPSAxMCwgY29sID0gInJlZCIpCnBrcy4xNjwtcmVhZC5kZWxpbSAoImRhdGEvQ2hJUF8xNnBrc19mb3JSLnR4dCIsIHNlcD0gIlx0IikKYWJsaW5lICh2ID0gcGtzLjE2JHBrLmNlbnRlciwgY29sID0gImdyZXkiKQp0ZXh0KChwa3MuMTYkcGsuY2VudGVyKSwgNzAsIGxhYmVscyA9IGMoMToxNiksICBjZXggPSAwLjgsIGZvbnQgPSAyICkKYGBgCgojIyMjIEZpZyA0QgpgYGB7ciBmaWcud2lkdGggPSAxMiwgZmlnLmhlaWdodCA9IDUsIGVjaG8gPSBGfQpwbG90cGxhcy5jaGlwKGNoaXAuc3BsaXQsIDQ4LCB5cmFuZ2UgPSBjKDAsODApKQojbGVnZW5kKCd0b3BsZWZ0JyxsZWdlbmQ9YygnQW1wbGlmaWNhdGlvbicsJ0RlcGxldGlvbicpLGNvbD1jKCdjeWFuJywnYmx1ZScpLGNleD0wLjgsYmc9J3doaXRlJywgbHR5PWMoMSwxKSxsd2Q9MikKYGBgCgoKIyMjIFRhYmxlIDE6IEhvdyBtYW55IENOVnMgd2VyZSBkZXRlY3RlZCBpbiBlYWNoIGFycmF5IChHRSBhbmQgQ2hJUCBkYXRhKT8KYGBge3J9CiMjIEZpcnN0IHdlIGNvbnNpZGVyIEdFIGRhdGEuIEZpbHRlciBzZWdtZW50cyBieSBzaWduaWZpY2FuY2UgYWNyb3NzIG1haW4gY2hyb21vc29tZS4KYWxsLmNsb25lLnNlZ3MuR0U8LSBzZWdzbW90JG91dHB1dAphbGwuY2xvbmUuc2Vncy5HRSRzZWcubGVuZ3RoIDwtIChhbGwuY2xvbmUuc2Vncy5HRSRsb2MuZW5kIC0gYWxsLmNsb25lLnNlZ3MuR0UkbG9jLnN0YXJ0KQpzZWdzLkdFLjIwayA8LSBzdWJzZXQgKGFsbC5jbG9uZS5zZWdzLkdFLCBzZWcubGVuZ3RoID49MjAwMDApCnNlZ3MuR0UuMjBrIDwtIHN1YnNldCAoc2Vncy5HRS4yMGssIGNocm9tID09ICJDaHIiICYgKHNlZy5tZWFuID49IDEgfCBzZWcubWVhbiA8PSAtMSkpCiNmb3IgcE5SQzIwMAojc2Vncy5HRS4yMGsucDIwMCA8LSBzdWJzZXQgKGFsbC5jbG9uZS5zZWdzLkdFLCBzZWcubGVuZ3RoID49MjAwMDApCnNlZ3MuR0UuMjBrLnAyMDAgPC0gc3Vic2V0IChzZWdzLkdFLjIway5wMjAwLCBjaHJvbSA9PSAicE5SQzIwMCIgJiAoc2VnLm1lYW4gPj0gMSB8IHNlZy5tZWFuIDw9IC0xKSkKI2ZvciBwTlJDMTAwCiNzZWdzLkdFLjIway5wMTAwIDwtIHN1YnNldCAoYWxsLmNsb25lLnNlZ3MuR0UsIHNlZy5sZW5ndGggPj0yMDAwMCkKc2Vncy5HRS4yMGsucDEwMCA8LSBzdWJzZXQgKHNlZ3MuR0UuMjBrLnAxMDAsIGNocm9tID09ICJwTlJDMTAwIiAmIChzZWcubWVhbiA+PSAxIHwgc2VnLm1lYW4gPD0gLTEpKQoKIyMgRGV0ZXJtaW5lIGhvdyBtYW55IHNpZ25pZmljYW50IHNlZ21lbnRzIHdlcmUgY29udGFpbmVkIHdpdGhpbiB3aGljaCBHRSBhcnJheXMgb24gbWFpbiBjaHJvbW9zb21lCmZyZXEucGVyLmFycmF5MjAgPC0gcGx5cjo6OmNvdW50KHNlZ3MuR0UuMjBrLCAiSUQiKQpoaXN0KGZyZXEucGVyLmFycmF5MjAkZnJlcSwgY29sID0gImdyZXkiLCBtYWluID0gIkRpc3RyaWJ1dGlvbiBvZiBwdXRhdGl2ZSBDTlZzIHdpdGhpbiBlYWNoIEdFIGFycmF5IiwgeGxhYiA9ICJOdW1iZXIgb2YgYXJyYXlzIikgCgojZm9yIHBOUkMxMDAKZnJlcS5wZXIuYXJyYXkyMC5wMTAwIDwtIHBseXI6Ojpjb3VudChzZWdzLkdFLjIway5wMTAwLCAiSUQiKQpoaXN0KGZyZXEucGVyLmFycmF5MjAucDEwMCRmcmVxLCBjb2wgPSAiZ3JleSIsIG1haW4gPSAiRGlzdHJpYnV0aW9uIG9mIHB1dGF0aXZlIENOVnMgd2l0aGluIGVhY2ggR0UgYXJyYXkiLCB4bGFiID0gIk51bWJlciBvZiBhcnJheXMiKSAKCiNmb3IgcE5SQzIwMApmcmVxLnBlci5hcnJheTIwLnAyMDAgPC0gcGx5cjo6OmNvdW50KHNlZ3MuR0UuMjBrLnAyMDAsICJJRCIpCmhpc3QoZnJlcS5wZXIuYXJyYXkyMC5wMjAwJGZyZXEsIGNvbCA9ICJncmV5IiwgbWFpbiA9ICJEaXN0cmlidXRpb24gb2YgcHV0YXRpdmUgQ05WcyB3aXRoaW4gZWFjaCBHRSBhcnJheSIsIHhsYWIgPSAiTnVtYmVyIG9mIGFycmF5cyIpIAoKYGBgCgpgYGB7cn0KIyMgTmV4dCB3ZSBjb25zaWRlciBjaGlwIGRhdGEuIEZpbHRlciBzZWdtZW50cyBieSBzaWduaWZpY2FuY2UgYXQgNWsgdGhyZXNob2xkCnRlc3Qkc2VnLmxlbmd0aCA8LSAodGVzdCRsb2MuZW5kIC0gdGVzdCRsb2Muc3RhcnQpCnNlZ3MuY2hpcC41ayA8LSBzdWJzZXQgKHRlc3QsIHNlZy5sZW5ndGggPj0gNTAwMCkKc2Vncy5jaGlwLjVrIDwtIHN1YnNldCAoc2Vncy5jaGlwLjVrLCBjaHJvbSA9PSAiQ2hyIiAmIChzZWcubWVhbiA+PSAwLjUgfCBzZWcubWVhbiA8PSAtMC41KSkKCiMjIERldGVybWluZSBob3cgbWFueSBzaWduaWZpY2FudCBzZWdtZW50cyB3ZXJlIGNvbnRhaW5lZCB3aXRoaW4gd2hpY2ggQ2hJUCBhcnJheXMgCmZyZXEucGVyLmFycmF5LmNoaXAuNSA8LSBwbHlyOjo6Y291bnQoc2Vncy5jaGlwLjVrLCAiSUQiKQpoaXN0KGZyZXEucGVyLmFycmF5LmNoaXAuNSRmcmVxLCBjb2wgPSAiZ3JleSIsIG1haW4gPSAiRGlzdHJpYnV0aW9uIG9mIHB1dGF0aXZlIENOVnMgd2l0aGluIGVhY2ggQ2hJUCBhcnJheSIsIHhsYWIgPSAiTnVtYmVyIG9mIGFycmF5cyIpCgpgYGAKCiMjIEZpZ3VyZSA1CkZyZXF1ZW5jeSBtYXAgb2YgYWxsIENoSVAgQ05Wcywgd2l0aCBJUyBlbGVtZW50cyBtYXJrZWQKCmBgYHtyfQojIyByZWFkIGluIElTSCB0YWJsZQppc2ggPC0gcmVhZC5kZWxpbShmaWxlID0gImRhdGEvMjAxNzA3MDNfSVNmaW5kZXJfSVNIX2VsZW1lbnRzLnR4dCIpCiMjIHJlYWQgaW4gcGVha3MgdmVjdG9yCnBlYWtzIDwtbG9hZCgiZGF0YS9DaGlwX3BlYWtfcmVnaW9ucy5SZGF0YSIpCmBgYAoKRmlnIDVBOiBJUyBlbGVtZW50cyBhcmUgZGV0ZWN0ZWQgd2l0aGluIENOViByZWdpb25zLgpgYGB7ciBmaWcud2lkdGggPSAxMiwgZmlnLmhlaWdodCA9IDUsIGVjaG8gPSBGfQpwbG90Y2hyX2NoaXAyKGNvcHltYXAgPSBjaGlwLnNwbGl0LCBuYXJyYXlzID0gNDgsIHltYXggPSA4MCwgaXNoX3RhYmxlID0gaXNoKQpsZWdlbmQoJ3RvcGxlZnQnLGxlZ2VuZD1jKCdDTlYnLCdJUycsICcxMCUgdGhyZXNob2xkJyksY29sPWMoJ2JsYWNrJyxyZ2IoMC4xLDAuMSwuOCwuMyksICdyZWQnKSxjZXg9MS4yLGJnPSd3aGl0ZScsIGx0eT1jKDEsMiksbHdkPTIpCmFibGluZShoID0gMTAsIGNvbCA9ICJyZWQiKQojcG9pbnRzKHggPSBzYW1wbGUocGVha3M3LCAxMDAwKSwgeSA9IGMocmVwKDIsMTAwMCkpLCBjb2wgPSAiZ3JlZW4iLCBwY2ggPTE2LCBjZXg9IC41KQoKYGBgCgoKRmlnIDVCOiBJUyBlbGVtZW50cyBhcmUgYXNzb2NpYXRlZCB3aXRoIENOViByZWdpb25zIGF0IGhpZ2hlciByYXRlIHRoYW4gZXhwZWN0ZWQgYnkgY2hhbmNlOiBib290c3RyYXBwaW5nIHJlc3VsdHMKYGBge3J9CnNldC5zZWVkKDg4NzYpCklTYm9vdCA8LSBmdW5jdGlvbihJU19udW1iZXIsIHBlYWtzKXsKCWJvb3Q9YygpCglmb3IoaSBpbiAxOjEwMDAwKXsKCUlTbGlzdD0gc2FtcGxlKDE6MjAxNDIzOSxJU19udW1iZXIpCQogCWJvb3RbaV09IGxlbmd0aCh3aGljaChJU2xpc3QgJWluJSBwZWFrcykpCgl9Cglib290Cn0KCiMjIG9mIElTIGVsZW1lbnRzIGluIGNociBwZWFrcyBmcm9tIENoSVAgZGF0YSAobm90ZTogSVMgdGFibGUgaXMgZm9yIGNocm9tb3NvbWUgb25seSkKaXMubiA8LSBsZW5ndGgoaXNoJFN0YXJ0W2lzaCRTdGFydCAlaW4lIHBlYWtzN10pCgppc2guYm9vdCA8LSBJU2Jvb3QoaXMubiwgcGVha3M3KQoKYGBgCmBgYHtyIGZpZy53aWR0aD01LCBmaWcuaGVpZ2h0PTQsIGVjaG89Rn0KaGlzdChpc2guYm9vdCwgY29sID0gImdyYXkiLCB4bGltID0gYygwLDE1KSwgeGxhYiA9ICJOdW1iZXIgb2YgSVMgZWxlbWVudHNcbiBpbiBDTlYgcmVnaW9ucyIsIGNleC5sYWI9MS4yLCBicmVha3MgPTEwKQphYmxpbmUoIHYgPSAxNCwgbHR5ID0gMikKYGBgCgoKIyMgQXBwZW5kaXgKYGBge3J9CnNlc3Npb25JbmZvKCkKYGBgCgoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkKYGBgCgoKTm90ZSB0aGF0IHRoZSBgZWNobyA9IEZBTFNFYCBwYXJhbWV0ZXIgd2FzIGFkZGVkIHRvIHRoZSBjb2RlIGNodW5rIHRvIHByZXZlbnQgcHJpbnRpbmcgb2YgdGhlIFIgY29kZSB0aGF0IGdlbmVyYXRlZCB0aGUgcGxvdC4K